#ifndef __CLIENTMSG_H__
#define __CLIENTMSG_H__

/**
 * @file ClientMsg.h
 * @author Lost
 * @date 一月 2020
 * @brief 
 * 客户端消息管理类
 */



#include "packet.pb.h"
#include "cs_login.pb.h"


#include "BlockNet.h"
#include "Singleton.h"

#include <string>
#include <map>
#include <vector>

using std::map;
using std::pair;
using std::vector;
using std::string;

/**
 * @brief 报文处理回调函数
 * @note 
 */
typedef int(*CALLBACK_MSG_HANDLE)(const string &pbRecvMessage);


/**
 * @brief 回报处理结构
 * @note 
 */
struct CallBackResHandle
{
    /*!< 回调函数 */
    CALLBACK_MSG_HANDLE pfResHandle;

    /*!< 注册时间 */
    int iRegistTime;
};


using std::string;
/**
 * @brief 客户端消息类
 */
class CClientMsg : public BlockNet, public CSingleton<CClientMsg>, public CNetBase
{
public:
    CClientMsg();
    ~CClientMsg();
public:
    virtual bool Init();

    /**
     * @brief 收到连接事件
     */
    virtual bool OnConnect(const int iSocket);

    /**
     * @brief 收到关闭事件
     */
    virtual bool OnClose(const int iSocket);

    /**
     * @brief 接收报文事件
     */
    virtual bool OnPacket(const int iSocket, char *pData, int iLen);

public:
    /**
     * @brief 检查是否已经连接服务器
     * @note 
     */
    inline bool IsConnected() { return m_iSocket != -1; }
    /**
     * @brief 发送报文
     * @note 返回发送字节，返回后数据不一定发送到网络层，有可能因为阻塞保存在缓存链表中
     */
    virtual int SendMsg(comm::EnmModuleCmd eModule, int iCmd, const google::protobuf::Message &csBody,
        CALLBACK_MSG_HANDLE pfMsgHandle, int64_t llRoleID = 0);

    /**
     * @brief 发送报文
     * @note 返回发送字节，返回后数据不一定发送到网络层，有可能因为阻塞保存在缓存链表中
     */
    virtual int SendMsg(const google::protobuf::Message &commPackage, CALLBACK_MSG_HANDLE pfMsgHandle);

    /**
     * @brief 创建报文头
     * @note 根据参数创建报文头,返回值为局部静态变量,不可引用且嵌套使用.
     */
    comm::Head& CreateHead( comm::EnmModuleCmd eModule, int iEnmCmd, int64_t ullRoleID = 0 );

public:
    /**
     * @brief 注册Res消息的处理函数
     * @note 返回是否注册成功,0成功,!=0不成功
     */
    int RegisResHandle(int iSeqID, CALLBACK_MSG_HANDLE pfResHandle);


    /**
     * @brief 注册Notity消息的处理函数
     * @note 返回是否注册成功,0成功,!=0不成功
     */
    int RegistNotifyHandle( int iCmd, CALLBACK_MSG_HANDLE pfNotifyHandle);

    /**
     * @brief 注销Notity消息的处理函数
     * @note 返回注销个数
     */
    int UnRegistNotifyHandle(int iCmd, CALLBACK_MSG_HANDLE pfNotifyHandle);

    /**
     * @brief 注销Notity消息的处理函数
     * @note 返回注销个数
     */
    int UnRegistNotifyHandleByCmd(int iCmd);

    /**
     * @brief 注销Notity消息的处理函数
     * @note 返回注销个数
     */
    int UnRegistNotifyHandleByHandle(CALLBACK_MSG_HANDLE pfNotifyHandle);

    /**
     * @brief 创建一个序列号
     * @note 
     */
    inline int CreateSeq() { return ++m_iSeqID; }

    /**
     * @brief 生成cmd号
     * @note
     */
    inline int CreateCmd(comm::EnmModuleCmd eModule, int iEnmCmd) { return eModule * 10000 + iEnmCmd; }

    /**
     * @brief 获得模块
     * @note
     */
    comm::EnmModuleCmd GetModuleFromCmd(int iCmd);
    /**
     * @brief 获得指令枚举
     * @note
     */
    inline int GetEnmCmd(int iCmd) { return iCmd % 10000; }

private:
    /*!< 回报处理池,key:seqid */
    typedef map<int, CallBackResHandle> ResHandleMap;
    ResHandleMap m_mapResMsgHandleMap;

    /*!< 通知处理池,key:Cmd */
    typedef vector<CALLBACK_MSG_HANDLE> NotifyHandleVec;
    typedef map<int, NotifyHandleVec > NotifyHandleMap;
    NotifyHandleMap m_mapNotifyHandleVecMap;

    /*!< 序列号 */
    int m_iSeqID;

    /*!< 套接字 */
    int m_iSocket;
};

#endif // __CLIENTMSG_H__
